package cn.iocoder.yudao.module.pay.framework.impl;

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.api.pay.order.dto.UnifiedOrderCreateDTO;
import cn.iocoder.yudao.module.api.pay.order.eums.UnifiedPayChannelEnum;
import cn.iocoder.yudao.module.api.pay.order.vo.UnifiedOrderVO;
import cn.iocoder.yudao.module.api.pay.refund.dto.UnifiedRefundCreateDTO;
import cn.iocoder.yudao.module.api.pay.refund.vo.UnifiedRefundVO;
import cn.iocoder.yudao.module.api.pay.transfer.dto.UnifiedTransferCreateDTO;
import cn.iocoder.yudao.module.api.pay.transfer.vo.UnifiedTransferVO;
import cn.iocoder.yudao.module.pay.framework.PayClient;
import cn.iocoder.yudao.module.pay.framework.PayClientConfig;
import cn.iocoder.yudao.module.pay.framework.PayException;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;

/**
 * 支付客户端的抽象类，提供模板方法，减少子类的冗余代码
 *
 * @author 芋道源码
 */
@Slf4j
public abstract class AbstractPayClient<CONFIG extends PayClientConfig> implements PayClient<CONFIG> {
    private final String channelCode;
    protected CONFIG channelConfig;

    @SuppressWarnings("unused")
    public AbstractPayClient(CONFIG channelConfig) {
        this(UnifiedPayChannelEnum.UNKNOWN.getCode(), channelConfig);
    }

    protected AbstractPayClient(String channelCode, CONFIG channelConfig) {
        this.channelCode = channelCode;
        this.channelConfig = channelConfig;
    }

    @Override
    public String getChannelCode() {
        return channelCode;
    }

    @Override
    public CONFIG getChannelConfig() {
        return channelConfig;
    }

    /**
     * 初始化
     */
    public final void init() {
        doInit();
        log.debug("[init][支付客户端({}) 初始化完成 {}]", getChannelCode(), getChannelConfig().getClass().getName());
    }

    /**
     * 自定义初始化
     */
    protected abstract void doInit();

    public final void refresh(CONFIG newConfig) {
        // 判断是否更新
        if (newConfig.equals(this.channelConfig)) {
            return;
        }
        log.info("[refresh][支付渠道配置({})发生变化，重新初始化]", getChannelCode());
        this.channelConfig = newConfig;
        // 初始化
        this.init();
    }

    // ============ 支付相关 ==========

    @Override
    public final UnifiedOrderVO unifiedOrder(UnifiedOrderCreateDTO dto) {
        log.debug("[unifiedOrder][支付客户端({}) request({})]", getChannelCode(), toJsonString(dto));
        ValidationUtils.validate(dto);
        // 执行统一下单
        UnifiedOrderVO orderVO;
        try {
            orderVO = doUnifiedOrder(dto);
            log.debug("[unifiedOrder][支付客户端({}) 发起付款成功] {}", getChannelCode(), orderVO);
        } catch (Throwable ex) {
            // 系统异常，则包装成 PayException 异常抛出
            log.error("[unifiedOrder][支付客户端({}) 发起付款异常]", getChannelCode(), ex);
            throw buildPayException(ex);
        }
        return orderVO;
    }

    protected UnifiedOrderVO doUnifiedOrder(UnifiedOrderCreateDTO dto) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedOrderVO getOrder(String payNo) {
        try {
            return doGetOrder(payNo);
        } catch (Throwable ex) {
            log.error("[getOrderByNo][支付客户端({}) payNo({})) 查询支付单异常]", getChannelCode(), payNo, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedOrderVO doGetOrder(String payNo) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedOrderVO parseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) {
        try {
            return doParseOrderNotify(params, body, headers);
        } catch (Throwable ex) {
            log.error("[parseOrderNotify][支付客户端({}) params({}) body({}) headers({}) 解析失败]",
                    getChannelCode(), params, body, headers, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedOrderVO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final boolean closeOrder(String payNo) {
        try {
            return doCloseOrder(payNo);
        } catch (Throwable ex) {
            log.error("[closeOrder][支付客户端({}) payNo({}) 关单异常]", getChannelCode(), payNo, ex);
            throw buildPayException(ex);
        }
    }

    protected boolean doCloseOrder(String payNo) throws Throwable {
        return false;
    }

    // ============ 退款相关 ==========

    @Override
    public final UnifiedRefundVO unifiedRefund(UnifiedRefundCreateDTO dto) {
        log.debug("[unifiedRefund][支付客户端({}) request({})]", getChannelCode(), toJsonString(dto));
        ValidationUtils.validate(dto);
        // 执行统一退款
        UnifiedRefundVO refundVO;
        try {
            refundVO = doUnifiedRefund(dto);
            log.debug("[unifiedRefund][支付客户端({}) 发起退款成功] {}", getChannelCode(), refundVO);
        } catch (Throwable ex) {
            // 系统异常，则包装成 PayException 异常抛出
            log.error("[unifiedRefund][支付客户端({}) 发起退款异常]", getChannelCode(), ex);
            throw buildPayException(ex);
        }
        return refundVO;
    }

    protected UnifiedRefundVO doUnifiedRefund(UnifiedRefundCreateDTO dto) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedRefundVO parseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) {
        try {
            return doParseRefundNotify(params, body, headers);
        } catch (Throwable ex) {
            log.error("[parseRefundNotify][支付客户端({}) params({}) body({}) headers({}) 解析失败]",
                    getChannelCode(), params, body, headers, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedRefundVO doParseRefundNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedRefundVO getRefund(String payNo, String refundNo) {
        try {
            return doGetRefund(payNo, refundNo);
        } catch (Throwable ex) {
            log.error("[getRefund][支付客户端({}) payNo({}) refundNo({}) 查询退款单异常]",
                    getChannelCode(), payNo, refundNo, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedRefundVO doGetRefund(String payNo, String refundNo) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedTransferVO unifiedTransfer(UnifiedTransferCreateDTO dto) {
        log.debug("[unifiedTransfer][支付客户端({}) request({})]", getChannelCode(), toJsonString(dto));
        UnifiedTransferVO transferVO;
        try {
            transferVO = doUnifiedTransfer(dto);
            log.debug("[unifiedTransfer][支付客户端({}) 发起转账成功] {}", getChannelCode(), transferVO);
        } catch (Throwable ex) {
            // 系统异常，则包装成 PayException 异常抛出
            log.error("[unifiedTransfer][支付客户端({}) 发起转账异常]", getChannelCode(), ex);
            throw buildPayException(ex);
        }
        return transferVO;
    }

    protected UnifiedTransferVO doUnifiedTransfer(UnifiedTransferCreateDTO dto) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedTransferVO getTransfer(String transferNo) {
        try {
            return doGetTransfer(transferNo);
        } catch (Throwable ex) {
            log.error("[getTransfer][支付客户端({}) transferNo({}) 查询转账单异常]",
                    getChannelCode(), transferNo, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedTransferVO doGetTransfer(String transferNo) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    @Override
    public final UnifiedTransferVO parseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
        try {
            return doParseTransferNotify(params, body, headers);
        } catch (Throwable ex) {
            log.error("[doParseTransferNotify][支付客户端({}) params({}) body({}) headers({}) 解析失败]",
                    getChannelCode(), params, body, headers, ex);
            throw buildPayException(ex);
        }
    }

    protected UnifiedTransferVO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
        throw new UnsupportedOperationException("待实现");
    }

    private ServiceException buildPayException(Throwable ex) {
        if (ex instanceof ServiceException exception) {
            return exception;
        }
        return new PayException(ex);
    }

}
